import AliyunLive from '@alicloud/live20161101'
import { Injectable } from '@nestjs/common'
import { ConfigService } from '@nestjs/config'
import NodeMediaServer from 'node-media-server'
import { RedisService } from '../redis/RedisService'
import { RoomStateService } from '../room/RoomStateService'

interface StreamingConfig {
  mediaServer: {
    rtmp: {
      host: string
      port: number
    }
    http: {
      host: string
      port: number
      mediaroot: string
    }
  }
  tencent: {
    secretId: string
    secretKey: string
    region: string
    pushDomain: string
    pullDomain: string
    pushKey: string
    urlExpireTime: number
  }
  aliyun: {
    accessKeyId: string
    accessKeySecret: string
    endpoint: string
    pushDomain: string
    pullDomain: string
    pushKey: string
    urlExpireTime: number
  }
  keyExpireTime: number
  streamKeySecret: string
}

@Injectable()
export class StreamingService {
  private redis: RedisService
  private roomState: RoomStateService
  private nms: NodeMediaServer
  private aliyunLive: any
  private io: any

  constructor(
    private readonly configService: ConfigService,
    redisService: RedisService,
    roomStateService: RoomStateService,
    io: any
  ) {
    this.redis = redisService
    this.roomState = roomStateService
    this.io = io

    const streamingConfig = this.configService.get<StreamingConfig>('streaming')

    // 初始化本地流媒体服务器
    this.nms = new NodeMediaServer({
      rtmp: {
        port: streamingConfig.mediaServer.rtmp.port,
        chunk_size: 60000,
        gop_cache: true,
        ping: 30,
        ping_timeout: 60,
      },
      http: {
        port: streamingConfig.mediaServer.http.port,
        allow_origin: '*',
      },
    })

    // 初始化阿里云直播
    this.aliyunLive = new AliyunLive({
      accessKeyId: streamingConfig.aliyun.accessKeyId,
      accessKeySecret: streamingConfig.aliyun.accessKeySecret,
      endpoint: streamingConfig.aliyun.endpoint,
      toMap: () => ({
        accessKeyId: streamingConfig.aliyun.accessKeyId,
        accessKeySecret: streamingConfig.aliyun.accessKeySecret,
        endpoint: streamingConfig.aliyun.endpoint,
      }),
    })

    this.setupMediaServer()
  }

  private setupMediaServer() {
    this.nms.run()

    this.nms.on('prePublish', async (id: string, StreamPath: string) => {
      const pathParts = StreamPath.split('/')
      const roomId = pathParts[1]
      const streamKey = pathParts[2]

      const validKey = await this.redis.get(`stream:key:${roomId}`)
      if (streamKey !== validKey) {
        const session = this.nms.getSession(id)
        session.reject()
      }
    })

    this.nms.on('postPublish', async (id: string, StreamPath: string) => {
      const roomId = StreamPath.split('/')[1]
      this.io.to(roomId).emit('stream_start', { roomId })
    })

    this.nms.on('donePublish', async (id: string, StreamPath: string) => {
      const roomId = StreamPath.split('/')[1]
      this.io.to(roomId).emit('stream_end', { roomId })
    })
  }
}
